"""
微信公众号发布器
"""

import requests
import json
from typing import Dict, Any, Optional
import time

from .base import BasePublisher
from ..core.config import get_settings
from ..core.logger import app_logger

settings = get_settings()


class WeChatPublisher(BasePublisher):
    """微信公众号发布器"""
    
    def __init__(self):
        self.api_base = "https://api.weixin.qq.com/cgi-bin"
        self.app_id = getattr(settings, 'WECHAT_APP_ID', None)
        self.app_secret = getattr(settings, 'WECHAT_APP_SECRET', None)
        self.access_token = None
        self.token_expires_at = 0
        super().__init__()
    
    def get_platform_name(self) -> str:
        return "微信公众号"
    
    def check_configuration(self) -> bool:
        """检查微信公众号API配置"""
        required_configs = [
            self.app_id,
            self.app_secret
        ]
        
        if all(config for config in required_configs):
            app_logger.info("微信公众号API配置完整")
            return True
        else:
            app_logger.warning("微信公众号API配置不完整，将使用模拟模式")
            return False
    
    async def _get_access_token(self) -> Optional[str]:
        """获取微信公众号访问令牌"""
        
        if not self.is_configured:
            return "mock_access_token"
        
        # 检查token是否已过期
        current_time = time.time()
        if self.access_token and current_time < self.token_expires_at:
            return self.access_token
        
        try:
            url = f"{self.api_base}/token"
            params = {
                "grant_type": "client_credential",
                "appid": self.app_id,
                "secret": self.app_secret
            }
            
            response = requests.get(url, params=params, timeout=30)
            
            if response.status_code == 200:
                data = response.json()
                if "access_token" in data:
                    self.access_token = data["access_token"]
                    # 提前5分钟过期，确保token有效性
                    self.token_expires_at = current_time + data.get("expires_in", 7200) - 300
                    app_logger.info("微信公众号访问令牌获取成功")
                    return self.access_token
                else:
                    app_logger.error(f"获取访问令牌失败: {data}")
                    return None
            else:
                app_logger.error(f"获取访问令牌失败: HTTP {response.status_code}")
                return None
                
        except Exception as e:
            app_logger.error(f"获取访问令牌异常: {e}")
            return None
    
    async def publish(self, content: str, **kwargs) -> Dict[str, Any]:
        """发布内容到微信公众号"""
        
        # 验证内容
        if not self.validate_content(content, max_length=2000):
            return self.format_response(False, error="内容验证失败")
        
        try:
            if self.is_configured:
                # 真实API调用
                result = await self._publish_to_wechat_api(content, **kwargs)
            else:
                # 模拟发布
                result = await self._mock_publish(content, **kwargs)
            
            if result["success"]:
                app_logger.info(f"微信公众号发布成功: {result.get('data', {}).get('post_id', 'mock_id')}")
            else:
                app_logger.error(f"微信公众号发布失败: {result.get('error', '未知错误')}")
            
            return result
            
        except Exception as e:
            app_logger.error(f"微信公众号发布异常: {e}")
            return self.format_response(False, error=str(e))
    
    async def _publish_to_wechat_api(self, content: str, **kwargs) -> Dict[str, Any]:
        """调用微信公众号API发布内容"""
        
        access_token = await self._get_access_token()
        if not access_token:
            return self.format_response(False, error="无法获取访问令牌")
        
        # 微信公众号需要先创建图文消息素材，然后群发
        try:
            # 1. 创建图文消息素材
            material_id = await self._create_news_material(access_token, content, **kwargs)
            if not material_id:
                return self.format_response(False, error="创建图文素材失败")
            
            # 2. 群发消息
            result = await self._send_mass_message(access_token, material_id, **kwargs)
            return result
            
        except Exception as e:
            return self.format_response(False, error=f"API调用失败: {e}")
    
    async def _create_news_material(self, access_token: str, content: str, **kwargs) -> Optional[str]:
        """创建图文消息素材"""
        
        url = f"{self.api_base}/material/add_news?access_token={access_token}"
        
        # 构建图文消息
        title = kwargs.get("title", content[:30] + "..." if len(content) > 30 else content)
        author = kwargs.get("author", "自动发布系统")
        digest = kwargs.get("digest", content[:120] + "..." if len(content) > 120 else content)
        
        articles = [{
            "title": title,
            "author": author,
            "digest": digest,
            "content": content.replace('\n', '<br>'),
            "content_source_url": kwargs.get("source_url", ""),
            "thumb_media_id": kwargs.get("thumb_media_id", ""),
            "show_cover_pic": 1,
            "need_open_comment": kwargs.get("need_open_comment", 0),
            "only_fans_can_comment": kwargs.get("only_fans_can_comment", 0)
        }]
        
        payload = {"articles": articles}
        
        try:
            response = requests.post(
                url, 
                data=json.dumps(payload, ensure_ascii=False).encode('utf-8'),
                headers={"Content-Type": "application/json; charset=utf-8"},
                timeout=30
            )
            
            if response.status_code == 200:
                data = response.json()
                if "media_id" in data:
                    return data["media_id"]
                else:
                    app_logger.error(f"创建图文素材失败: {data}")
                    return None
            else:
                app_logger.error(f"创建图文素材失败: HTTP {response.status_code}")
                return None
                
        except Exception as e:
            app_logger.error(f"创建图文素材异常: {e}")
            return None
    
    async def _send_mass_message(self, access_token: str, media_id: str, **kwargs) -> Dict[str, Any]:
        """群发消息"""
        
        url = f"{self.api_base}/message/mass/sendall?access_token={access_token}"
        
        # 群发给所有用户（可以根据需要修改为特定分组）
        payload = {
            "filter": {
                "is_to_all": True
            },
            "mpnews": {
                "media_id": media_id
            },
            "msgtype": "mpnews",
            "send_ignore_reprint": 0
        }
        
        try:
            response = requests.post(
                url,
                data=json.dumps(payload, ensure_ascii=False).encode('utf-8'),
                headers={"Content-Type": "application/json; charset=utf-8"},
                timeout=30
            )
            
            if response.status_code == 200:
                data = response.json()
                if data.get("errcode") == 0:
                    return self.format_response(True, {
                        "post_id": str(data.get("msg_id", "")),
                        "msg_data_id": str(data.get("msg_data_id", "")),
                        "status": "sent"
                    })
                else:
                    return self.format_response(False, error=data.get("errmsg", "发送失败"))
            else:
                return self.format_response(False, error=f"HTTP {response.status_code}")
                
        except Exception as e:
            return self.format_response(False, error=f"发送消息异常: {e}")
    
    async def _mock_publish(self, content: str, **kwargs) -> Dict[str, Any]:
        """模拟发布（用于测试）"""
        
        import time
        mock_id = f"wx_{int(time.time())}"
        
        return self.format_response(True, {
            "post_id": mock_id,
            "msg_data_id": f"data_{mock_id}",
            "status": "sent",
            "title": kwargs.get("title", content[:30]),
            "note": "这是模拟发布，未实际发送到微信公众号"
        })
    
    async def delete_post(self, post_id: str) -> bool:
        """删除已发布的消息（微信公众号不支持删除已发布消息）"""
        
        app_logger.warning("微信公众号不支持删除已发布的消息")
        return False
    
    async def get_post_status(self, post_id: str) -> Dict[str, Any]:
        """获取消息发送状态"""
        
        if not self.is_configured:
            return {
                "exists": True,
                "status": "sent",
                "note": "模拟状态"
            }
        
        # 微信公众号可以通过msg_id查询群发状态
        access_token = await self._get_access_token()
        if not access_token:
            return {
                "exists": False,
                "status": "error",
                "error": "无法获取访问令牌"
            }
        
        try:
            url = f"{self.api_base}/message/mass/get?access_token={access_token}"
            payload = {"msg_id": post_id}
            
            response = requests.post(
                url,
                data=json.dumps(payload),
                headers={"Content-Type": "application/json"},
                timeout=30
            )
            
            if response.status_code == 200:
                data = response.json()
                if data.get("errcode") == 0:
                    return {
                        "exists": True,
                        "status": data.get("msg_status", "unknown"),
                        "total_count": data.get("total_count", 0),
                        "filter_count": data.get("filter_count", 0),
                        "sent_count": data.get("sent_count", 0),
                        "error_count": data.get("error_count", 0)
                    }
                else:
                    return {
                        "exists": False,
                        "status": "not_found",
                        "error": data.get("errmsg", "查询失败")
                    }
            else:
                return {
                    "exists": False,
                    "status": "error",
                    "error": f"HTTP {response.status_code}"
                }
                
        except Exception as e:
            app_logger.error(f"获取消息状态异常: {e}")
            return {
                "exists": False,
                "status": "error",
                "error": str(e)
            }
    
    async def test_connection(self) -> bool:
        """测试微信公众号API连接"""
        
        if not self.is_configured:
            return True  # 模拟模式总是可用
        
        try:
            access_token = await self._get_access_token()
            if access_token:
                app_logger.info("微信公众号API连接测试成功")
                return True
            else:
                app_logger.error("微信公众号API连接测试失败")
                return False
                
        except Exception as e:
            app_logger.error(f"微信公众号API连接测试异常: {e}")
            return False